﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GnufBase.h"
#include "GnufWithUserData.h"

namespace gnuf {

    class ValueInputGroup;
    class ValueInputSet;

    class GNUF_BASE_EXPORT ValueInputBase 
        : public gcmp::WeakReferenceable
        , public gnuf::WithUserData
    {
        CANNOT_COPY_OR_ASSIGN(ValueInputBase)
        DEFINE_CAST_BASE(gnuf::ValueInputBase)
    public:
        ValueInputBase(std::uint16_t);
        virtual ~ValueInputBase();

        ValueInputSet * rootGroup();
        const ValueInputSet * rootGroup() const;
        ValueInputGroup * group() { return m_pGroup; }
        const ValueInputGroup * group() const { return m_pGroup; }

        inline std::uint16_t id() const { return m_id; }

    protected:
        void sendChangeEvent();

    private:
        const std::uint16_t m_id;

        friend class ValueInputGroup;
        ValueInputGroup * m_pGroup;
    };

    template <class TValue>
    class ValueInput : public ValueInputBase
    {
    protected:
        ValueInput(std::uint16_t id, const TValue& value)
            : ValueInputBase(id)
            , m_value(value)
            , m_enable(true)
        {}

        virtual ~ValueInput() {}

    public:
        inline void setValue(const TValue& value) { setValue(value, false); }
        inline const TValue& value() const { return m_value; }
        inline bool isEnable() const { return m_enable; }
        inline void setEnable(bool enable)
        {
            if (m_enable == enable)
            {
                return;
            }
            m_enable = enable;
            onPostAbilityChanged();
        }
    protected:
        virtual bool onIsEqualTo(const TValue& value) const { return (value == m_value); }
        virtual void onPreValueChanged(const TValue&) {}
        virtual void onPostValueChanged() {}
        virtual void onPostAbilityChanged() {}
        void setValueNoiselessly(const TValue& value) { setValue(value, true); }

    private:
        inline void setValue(const TValue& value, const bool noiselessly)
        {
            if (onIsEqualTo(value)) {
                return;
            }

            if (!noiselessly) {
                onPreValueChanged(value);
            }

            // Changed.
            m_value = value;

            if (!noiselessly) {
                onPostValueChanged();
            }
        }
        bool m_enable;
        TValue m_value;
    };

}
